package mirrormonkey.rpc.module;

import mirrormonkey.framework.entity.SyncEntity;
import mirrormonkey.rpc.RpcListener;
import mirrormonkey.rpc.member.RpcMethodData;
import mirrormonkey.rpc.messages.RpcErrorMessage;
import mirrormonkey.rpc.messages.RpcResultMessage;
import mirrormonkey.rpc.proxy.RpcInvocationHandler;

import com.jme3.network.MessageConnection;

public class RegisteredCall {

	public final CallRegistry registry;

	public final int id;

	public final RpcMethodData methodData;

	public final MessageConnection expectResultFrom;

	public final RpcInvocationHandler<?> handler;

	public final float timeout;

	public float passedTime;

	public final SyncEntity entity;

	public RegisteredCall(CallRegistry registry, RpcMethodData methodData,
			MessageConnection expectResultFrom,
			RpcInvocationHandler<?> handler, float timeout, SyncEntity entity) {
		if (handler.listeners.isEmpty()) {
			id = CallRegistry.NO_RESPONSE_EXPECTED;
		} else {
			id = registry.registerCall(this);
		}

		this.registry = registry;
		this.methodData = methodData;
		this.expectResultFrom = expectResultFrom;
		this.handler = handler;
		this.timeout = timeout;
		this.entity = entity;
	}

	public void resultArrived(MessageConnection source,
			RpcResultMessage castMessage) {
		if (!expectResultFrom.equals(source)) {
			throw new RuntimeException();
		}
		for (RpcListener i : handler.listeners) {
			i.resultArrived(this, source,
					methodData.extractResult(castMessage.result));
		}
		registry.removeCall(this);
	}

	public void errorArrived(MessageConnection source,
			RpcErrorMessage castMessage) {
		if (!expectResultFrom.equals(source)) {
			throw new RuntimeException();
		}
		for (RpcListener i : handler.listeners) {
			i.errorArrived(this, source, castMessage.message);
		}
	}

	public void update(float tpf) {
		if ((passedTime += tpf) >= timeout) {
			for (RpcListener i : handler.listeners) {
				i.timedOut(this);
			}
			registry.removeCall(this);
		}
	}

}
